package org.NooLab.texx;


// http://www.slideshare.net/regarde/web-meets-world-2009


import java.io.IOException;
import java.util.Random;

import org.NooLab.utilities.files.DFutils;
import org.NooLab.utilities.logging.PrintLog;

import org.NooLab.utilities.resources.ResourceLoader;

 

import org.NooLab.texx.app.*;
import org.NooLab.texx.app.up.IniProperties;
import org.NooLab.texx.components.*;
//import org.NooLab.texx.env.communication.GlueBindings;
//import org.NooLab.texx.env.communication.GlueClientAdaptor;
import org.NooLab.texx.properties.TexxAppProperties;
import org.NooLab.texx.properties.TexxProperties;

import org.NooLab.texx.storage.*;

/**
 * 
 * if TEXX is started in directory mode, it should start
 * docoserv for handling the directory, then using the 
 * content of the database
 * 
 * the same mechanism applies to crawling web docs 
 * 
 *  

	
 * 
 * 
 *
 */
public class TexxFactory implements TexxFactoryClientIntf{

	public static final int _INSTANCE_TYPE_DEFAULT = 0;
	public static final int _GLUE_MODULE_ENV_NONE  = 0;
	
	public static final int _INSTANCE_TYPE_SERVICE = 1;
	public static final int _INSTANCE_TYPE_EXPLICIT = 2;
	public static final int _INSTANCE_TYPE_EXPLICIT_DIR = 3;
	public static final int _INSTANCE_TYPE_EXPLICIT_LIST = 4;
	
	// this package must exist
	String cfgPluggResourceJarPath = "org/NooLab/texx/plugg/resources/builtinscatalog-xml" ;
	String cfgSqlResourceJarPath   = "org/NooLab/texx/resources/sql/" ; // trailing / needed !!	
	
	// TexxAppGeneralPropertiesIntf texxProperties;
	static TexxProperties texxProperties;
	TexxAppProperties texxAppProperties;
	TexxProcessControlIntf txxProcessControl;

	TexxRequestPackage txxRqPkg;
	
	private TexxFactory factory;
	public TexxApplicationEventIntf appInformer; 

	private static int factoryMode;

	public Texx texxModule;
	
	int glueModuleMode = 0;
	// GlueClientAdaptor glueClient ;
	// GlueBindings glueBindings;
	
	DFutils fileutil = new DFutils();
	PrintLog out = new PrintLog(2, true, "[SomFluid-factory]");
	private WorkerObjects workerObjects;
	private Random random;
	
	
	// ------------------------------------------------------------------------
	public TexxFactory (TexxProperties props, int factorymode){
		
		if (props.getMessagingActive()){
			/*
			glueBindings = new GlueBindings( this, props);
			/* this is purely physical, 
			 	- no logics, 
				- no schemes for interpreting, or composing messages
				- no interfaces
			
			glueClient = new GlueClientAdaptor( glueBindings, props) ;
			glueClient.start();
			*/
		}
		
		
		txxProcessControl = new TexxProcessControl(this); 
		
		texxProperties = props;
		factoryMode = factorymode;
		
		factory = this;
		texxProperties.setFactoryParent( this );

		out.setPrefix("[Texx-factory]");

		texxProperties.getPersistenceSettings().setConfigSqlResourceJarPath(cfgSqlResourceJarPath) ;
		
		texxProperties.getPersistenceSettings().setAppNameShortStr("texx") ;
		
		
		try {
			(new AlgorithmDeclarationsLoader(texxProperties)).load() ;
			
		} catch (Exception e) {
			out.printErr(1, e.getMessage()+"... trying to recover...");
			
			try {
				// last minute check for resources
				if (checkAlgorithmsConfigPath()) {

					(new AlgorithmDeclarationsLoader(texxProperties)).load();

				} else {
					out.printErr(1, e.getMessage() + "attempt to recover failed, thus exiting...");
					System.exit(-7);
				}
				
			} catch (Exception e1) {
				out.printErr(1, e.getMessage() + "attempt to recover failed, thus exiting...");
				System.exit(-7);
			}
			String algorithmsConfigPath = texxProperties.getAlgorithmsConfigPath();
			out.printErr(1, "The attempt to recover succeeded, folder for declaration files is now : "+algorithmsConfigPath);
			
		}
		
		texxModule = new Texx( this );
		
		// random = new Random();
		// random.setSeed(192837465) ;
		
	}
	// ------------------------------------------------------------------------
	

	public TexxFactory( TexxAppProperties appProperties ){
		
		

		try {
			
			 
			factoryMode = TexxFactory._INSTANCE_TYPE_DEFAULT ;
			texxProperties = appProperties.getPropertiesConnection() ;
			texxAppProperties = appProperties;
 			
			factory = this;
			texxProperties.setFactoryParent( this );
			appProperties.setFactoryParent( this );
			  
			
			// needed: a common interface for this aspect
			(new AlgorithmDeclarationsLoader(texxProperties)).load() ;
			
			texxProperties.getPersistenceSettings().setConfigSqlResourceJarPath(cfgSqlResourceJarPath) ;
			
			
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(-7);
		}

		
	}
	
	public static TexxFactory get(TexxProperties props) {
		
		return new TexxFactory( props,1 );
	}

	public static TexxFactoryClientIntf get(){
		// we return a restricted interface ... which offers just the construction of some objects,
		// BUT NOT of the SomFluid !!!
		
		TexxProperties txprops = new TexxProperties ();
		return  (TexxFactoryClientIntf)(new TexxFactory( txprops,3 ));
	}



	private boolean checkAlgorithmsConfigPath() throws Exception {
		
		boolean rB=false;
		String outpath="";
		// loading "builtinscatalog.xml" which is necessary for global indexing and activation of built-in algorithms
		String algorithmsConfigPath  = texxProperties.getAlgorithmsConfigPath(); 
		String bic = fileutil.createpath(algorithmsConfigPath , "builtinscatalog.xml"); 
			
			
		if ((fileutil.direxists(algorithmsConfigPath )==false) || (fileutil.fileexists(bic)==false)){
			ProjectSpaceMaintenance psm = new ProjectSpaceMaintenance();
			
			ResourceLoader rsrcLoader = new ResourceLoader();   
			rB = rsrcLoader.loadTextResource( this.getClass(), cfgPluggResourceJarPath ) ;
			if (rB){  
				
				// create a directory structure, create the file and adjust the settings
				if (fileutil.direxists(algorithmsConfigPath )){
					outpath = algorithmsConfigPath;
				}else{
					psm = new ProjectSpaceMaintenance();
					psm.establishCatalogFolder();
				}
				
				String filename = fileutil.createpath( outpath,"builtinscatalog.xml" );
				
				fileutil.writeFileSimple(filename, rsrcLoader.getTextResource()) ;
				rB = fileutil.fileexists(filename) ;
			}
		}
		
		return rB;
	}

	
	public static boolean projectSpaceExists(String psLabel) {
		boolean rB= true;
		try {
		
			ProjectSpaceMaintenance psm = new ProjectSpaceMaintenance();
			rB = psm.projectSpaceExists( psLabel ) >= 0;
			
			
		} catch (Exception e) {
			System.err.println(e.getMessage());
		}
		
		return rB;
	}



	public static void completeProjectSpace() throws Exception {
		 
		 // SomFluidFactory.projectSpaceExists() 
		String pslabel = IniProperties.lastProjectName;
		
		String texxAppContext = texxProperties.getApplicationContext();
		
		if (texxAppContext.contentEquals(TexxProperties._APP_CONTEXT_ITEXX)==false){
			ProjectSpaceMaintenance psm = new ProjectSpaceMaintenance();
			psm.completeProjectSpaceDirectories() ;
		}

	}



	public static boolean organizeRawProjectData() {
		//
		String dataSourceFile = "" ;
		boolean rB=false;
		
		ProjectSpaceMaintenance psm = new ProjectSpaceMaintenance();
		psm.organizeRawProjectData();
		
		dataSourceFile = psm.getDataSourceFile();
		
		rB = DFutils.fileExists(dataSourceFile);
		
		if (rB){
			IniProperties.dataSource = dataSourceFile;
		}
		return rB;
	}

	// ....................................................
	
	
	public TexxProperties getTxxProperties() {
		return texxProperties;	
	}
	

	public TexxProcessControlIntf getSomProcessControl() {
		return txxProcessControl;
	}



	public void saveStartupTrace(int instanceTypeTxx, String traceInfo) {
		
		String userdir, cfgTraceFile;
		
		userdir = fileutil.getUserDir();
		
		cfgTraceFile = fileutil.createpath(userdir, "texx-"+instanceTypeTxx+".startup") ;
		
		
		fileutil.writeFileSimple(cfgTraceFile,traceInfo); 

		
	}


	public WorkerObjects getWorkerObjects() {
		return workerObjects;
	}


	public PrintLog getOut() {
		
		return out;
	}


	@Override
	public TexxRequestPackageIntf createRequestPackage() {
		// 
		TexxRequestPackageIntf trp = (TexxRequestPackageIntf) new TexxRequestPackage();
		return trp;
	}

	
	// TexxProperties._WORKER_TYPE_DEFAULT, TexxFactory._INSTANCE_TYPE_DEFAULT );
	public <T> Object createTask( int workertype, int instancetype) {
		 
		return createTask(  workertype, instancetype, "" ); // use GUID.randomvalue() to establish a admin-library of tasks
	}
	

	public <T> Object createTask( int instancetype) {
		 
		return createTask(  TexxProperties._WORKER_TYPE_DEFAULT, instancetype, "" ); // use GUID.randomvalue() to establish a admin-library of tasks
	}

	
	public <T> Object createTask( int workertype, int instancetype, String guidId) {
		
		TexxTask txxtask ;
		String descr="The requested type of instance to be created is unknown, no task has been created." ;
		
		TexxClassTaskIntf taskclass =null;
		
		
		if (instancetype == TexxFactory._INSTANCE_TYPE_DEFAULT ){ // sth like SomFluidProperties._SOMTYPE_MONO
			
			txxtask = new TexxTask( guidId, TexxTask._TASK_DEFAULT );
			txxtask.workType = workertype;
			
			taskclass = (TexxClassTaskIntf) (txxtask);
			descr="A task has been created, type = <TASK_DEFAULT>";
		}

		out.print(2, descr) ;
		return taskclass;
	}


	public TexxIntf getMainModule(){
	
		if (texxModule==null){
			 
			texxModule = new Texx( this);
		}
		
		
		try {
			
			//just starts the loop that will accept the tasks (incl. prepaing the Db
			texxModule.start();
			
		} catch (Exception e) {
			texxModule = null;
			e.printStackTrace();
		} 
		
		return texxModule ;
	}
	
		
	


	/** 
	 * takes the task and produces the SOM, usually, if not set otherwise, 
	 * it also will start the process
	 * @return 
	 * @throws Exception  
	 */
	public  void produce( Object texxTask ) throws Exception {
	
		TexxTask texxFactoryTask ;
		
		try{
	

			// now heading towards the SomFluid
			texxFactoryTask = (TexxTask)texxTask;
			
			saveTaskTrace(texxTask);
			
			// creating the main module and starting the task loop
			getMainModule();
			
			if (texxModule==null){
				throw(new Exception("The main module has not been intantiated properly: exiting..."));
			}

			/*
			 * 
			 * any further helper structures here
			 * 
			 */
			
			if (texxFactoryTask.getStartMode() == 1){
				
				// somFluidModule.start();   // nothing happens without providing a task
				texxModule.addTask( texxFactoryTask );
				// refers to class "Texx"
			}else{
				if (texxFactoryTask.getStartMode() >=100){
					// set a delayed start in a dedicated process
					InternalWorkerModuleStarter _starter = new InternalWorkerModuleStarter( texxFactoryTask ); 
				}
			}

		}catch(Exception e){
			
		}
	}
	/**
	 * 
	 * gets automatically called when a task is getting produced by the factory
	 * @param sfTask
	 */
	public void saveTaskTrace( Object sfTask  ) {
	
		String dir="",fileName="";
		int stype = texxProperties.getWorkerType();

		FileOrganizer fileorg = new FileOrganizer ();
	 
		if (texxAppProperties!=null){
			fileorg.setPropertiesBase(texxAppProperties);
		}else{
			fileorg.setPropertiesBase(texxProperties);
		}
	 
		
		dir = fileorg.getObjectStoreDir();

		dir = DFutils.createPath( dir, "task/"+stype+"/");
		fileName = DFutils.createPath( dir, TexxTask._TRACEFILE);
		
		
		
		// now loading the desired properties into a new object;
		ContainerStorageDevice storageDevice ;
		storageDevice = new ContainerStorageDevice();
		
		storageDevice.storeObject( sfTask, fileName) ;
		
		DFutils.reduceFileFolderList( dir,1,".trace",20) ;
	}


	class InternalWorkerModuleStarter implements Runnable {
		
		Thread sfmStarter;
		int _delay;
		TexxTask texxTask;
		
		public InternalWorkerModuleStarter( TexxTask sft ){
		
			texxTask = sft; 
			_delay = texxTask.getStartMode() ;
			
			sfmStarter = new Thread(this,"sfmStarter") ;
			sfmStarter.start() ;
		}

		@Override
		public void run() {
			 
			out.delay(_delay) ;
			
			try {
				
				texxModule.start();
				
				// nothing happens without providing a task
				texxModule.addTask( texxTask );
				
			} catch (Exception e) {
				e.printStackTrace();
			}   
			
		}
	}


	public int loadSource() {
		// 
		return 0;
	}


	public void testingTikaServerConnection() {
		 
		// texxModule.testingTikaServerConnection(); 
	}


	public void restartExternalServer(int listenport, int sendport) {
		
		String ports;
		
		ports = " -in:"+listenport+"  -out:"+sendport;
		
		try {
			
			// TODO: path must be dynamical !!!!!!!!!!!!!!!!
			String rootfolder = this.texxModule.texxProperties.getSystemRootDir();
			String exec = DFutils.createPath(rootfolder, "bin/NooLabTikaServer.jar") ;
			
			if (DFutils.fileExists(exec)==false){
				out.printErr(1, "restartExternalServer() failed, file not found by \n"+ exec);
				System.exit(-9) ;  // TODO check that !!!
			}
			Runtime.getRuntime().exec("cmd /c start "+exec+" "+ports);
			
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	
	
	
}
